﻿using Microsoft.Practices.Unity;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Web.Mvc;

using ERPStore.Extensions;
using System.Configuration;
using Microsoft.Practices.Unity.Configuration;

namespace ERPStore.Web.Start
{
	public class UnityConfig
	{
		private static string m_Host;
		private static string m_RootPath;

		#region Unity Container
		private static Lazy<IUnityContainer> container = new Lazy<IUnityContainer>(() =>
		{
			var container = ERPStore.GlobalConfiguration.Configuration.DependencyResolver.GetContainer();
			RegisterTypes(container);
			return container;
		});

		/// <summary>
		/// Gets the configured Unity container.
		/// </summary>
		public static IUnityContainer GetConfiguredContainer(System.Web.HttpContextBase ctx)
		{
			m_Host = ctx.Request.Url.Host;
			m_RootPath = ctx.Server.MapPath("/");
			return container.Value;
		}
		#endregion

		/// <summary>Registers the type mappings with the Unity container.</summary>
		/// <param name="container">The unity container to configure.</param>
		/// <remarks>There is no need to register concrete types such as controllers or API controllers (unless you want to 
		/// change the defaults), as Unity allows resolving a concrete type even if it was not previously registered.</remarks>
		public static void RegisterTypes(IUnityContainer container)
		{
			// Enregistrement des services
			container.RegisterType<ERPStore.Logging.ILogger, ERPStore.Logging.DiagnosticsLogger>(new PerResolveLifetimeManager());
			container.RegisterType<Services.IOptimizationService, Services.VoidOptimizationService>(new ContainerControlledLifetimeManager());
			container.RegisterType<Services.IEmailTemplateService, Services.EmailTemplateService>(new ContainerControlledLifetimeManager());
			container.RegisterType<Services.IModelMetadataRegistrationService, Services.ModelMetatdataRegistrationService>();
			container.RegisterType<Services.IRewriterService, Services.RewriterService>(new ContainerControlledLifetimeManager());
			container.RegisterType<ERPStore.Services.IValidatorService, Services.FluentValidatorService>(new ContainerControlledLifetimeManager());

			// Routes registration service for localization
			container.RegisterType<Services.IRoutesRegistrationService, ERPStore.Web.Routing.ERPStoreRoutes>(new ContainerControlledLifetimeManager());

			// EmailViewRenderer Configuration 
			var emailInjectionMembers = new InjectionMember[] 
			{
				new InjectionConstructor(
					ViewEngines.Engines,
					m_Host,
					"Emailer"
				)
			};
			container.RegisterType<Mail.IEmailViewRenderer, Mail.EmailViewRenderer>(emailInjectionMembers);

			LoadConfigurationOverrides(container);

			GlobalConfiguration.Configuration.Logger.Debug("container initialized");
		}

		private static void LoadConfigurationOverrides(IUnityContainer container)
		{
			var path = m_RootPath;

			// Chargement des services et overriding a partir du fichier
			// de configuration unity.config
			var map = new ExeConfigurationFileMap();
			var unityConfigFileName = ERPStore.Configuration.ConfigurationSettings.AppSettings["unityConfigFileName"] ?? "unity.config";
			map.ExeConfigFilename = System.IO.Path.Combine(path, unityConfigFileName);
			var config = ConfigurationManager.OpenMappedExeConfiguration(map, ConfigurationUserLevel.None);
			var section = (UnityConfigurationSection)config.GetSection("unity");
			if (section == null)
			{
				return;
			}

			try
			{
				section.Configure(container);
			}
			catch
			{
				var registrations = section.Containers[0].Registrations;
				// Check du mapping dans le fichier de config
				var fileNameList = registrations.Select(i => i.TypeName.Split(',')[1].Trim()).Distinct();
				foreach (var fileName in fileNameList)
				{
					var f = System.IO.Path.Combine(path, fileName + ".dll");
					if (System.IO.File.Exists(f))
					{
						continue;
					}
					f = System.IO.Path.Combine(path, "bin", fileName + ".dll");
					if (System.IO.File.Exists(f))
					{
						continue;
					}

					throw new System.IO.FileNotFoundException("File does not exists : " + f);
				}

				var message = string.Empty;
				foreach (var typeEntry in registrations)
				{
					Type fromType, toType;

					try
					{
						fromType = Type.GetType(typeEntry.TypeName, true);
						message = message + "FromType : " + typeEntry.TypeName + "\r\n";
					}
					catch
					{
						throw new Exception("Could not create the contract type: " + typeEntry.TypeName);
					}

					try
					{
						toType = Type.GetType(typeEntry.MapToName, true);
						message = message + "ToType : " + typeEntry.MapToName + "\r\n";
					}
					catch
					{
						throw new Exception("Could not create the mapped type: " + typeEntry.MapToName);
					}
				}

				throw new Exception("unity.config failed : " + message);
			}
		}

	}
}
